
"""
    pycoopiler - a compiler developed for PCS2056 course (Compilers) at Poli-USP
    Copyright (C) 2008 Andre Felipe Santos    
    Copyright (C) 2008 Rodrigo Rodrigues da Silva

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
"""

from pycoopiler.token import token
from pycoopiler.codegen import codegen
import logging

class semantico:
    
    def __init__(self, _file):
        self.separator = "=============================================================="
        self.SEMICOLON = ";"
        self.code = codegen(_file)   
        self.oplist = ("+", "-", "*", "/")
        self.oppreced = ("*", "/")
        self.cont = 0
        self.operators = ["#"]
        self.operands = ['#']
        
    
    def exp_gen_code(self):
        logging.debug("acao semantica: exp_gen_code")
        logging.debug("\t operators: " + str(self.operators))
        logging.debug("\t operands: " + str(self.operands))
        
        operator = self.operators.pop()
        logging.debug("\t operator: " + operator)
        operand_b = self.operands.pop()
        logging.debug("\t operand_b: " + operand_b)
        operand_a = self.operands.pop()
        logging.debug("\t operand_a: " + operand_a)
        
        if operand_b.isdigit():
            label = "CONST" + str(self.cont)
            self.code.const(operand_b, label)
            operand_b = label
            self.inc_cont()
            
        if operand_a.isdigit():
            label = "CONST" + str(self.cont)
            self.code.const(operand_a, label)
            self.code.load(label)
            self.inc_cont()
        else:
            self.code.load(operand_a)
        
        if operator == '+':
            self.code.add(operand_b)
        elif operator == '-':
            self.code.sub(operand_b)
        elif operator == '*':
            self.code.mul(operand_b)
        elif operator == '/':
            self.code.div(operand_b)
        else: raise Exception("Operador invalido: " + operator)
        
        self.inc_cont()
        label = "TEMP" + str(self.cont)
        self.code.save(label)
        self.operands.append(label)
        

    #Acoes semanticas: para o token recebido, executam acao    
    def exp_push_id(self, value):
        logging.debug("acao semantica: exp_push_id: " + value)
        #ver se o id esta na TS, senao dar erro pois nao esta definido!
    	self.operands.append(value)
    
    def exp_push_num(self, value): 
        logging.debug("acao semantica: exp_push_num: " + value)
        #se nao estiver na ts coloca
        self.operands.append(value)
        
    def exp_push_ocb(self):
        logging.debug("acao semantica: exp_push_ocb")
    	self.operators.append("(")
    	
    def do_nothing(self):
    	pass
    	
    def exp_verif_ocb(self):
    	if self.operators[-1] == '(':
    		self.operators.pop()
    	else:
    		self.exp_gen_code()
    		self.exp_verif_ocb()
    
    def exp_verif_operand_push_add(self):
    	if self.operators[-1] in self.oplist:
    			self.exp_gen_code()
    			self.exp_verif_operand_push_add()
    	else:
    		self.operators.append("+")
    	
    def exp_verif_operand_push_sub(self):
    	if self.operators[-1] in self.oplist:
    			self.exp_gen_code()
    			self.exp_verif_operand_push_sub()
    	else:
    		self.operators.append("-")
    
    def exp_verif_operand_push_mul(self):
    	if self.operators[-1] in self.oppreced:
    			self.exp_gen_code()
    			self.exp_verif_operand_push_mul()
    	else:
    		self.operators.append("*")
    	
    def exp_verif_operand_push_div(self):
    	if self.operators[-1] in self.oppreced:
    			self.exp_gen_code()
    			self.exp_verif_operand_push_div()
    	else:
    		self.operators.append("/")
    	
    def exp_verif_emptystack(self):
    	if len(self.operators) != 1:
    		self.exp_gen_code()
    		self.exp_verif_emptystack
    	
    def no_element(self):
    	raise Exception ("Esperava-se identificador, numero ou '('")
    	
    def wrong_exp(self):
    	raise Exception ("Expressao incorreta")
    	    	
    def no_ccb(self):
    	raise Exception ("Esperava-se ')'")
 
    def inc_cont(self):
        self.cont = self.cont+1
    
